package com.base.common.util.collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;

import com.base.common.base.CreatorFactory;
import com.base.common.base.SplitReadWriteLock;

/**
 * 本类目前不可用。有bug
 * 
 * @author yanjiaqiang
 * @date 2010-12-30
 * @version $Id: ConcurrentMultiValueMap.java 7 2011-07-15 04:24:04Z JiaqiangYan@gmail.com $
 */
public class ConcurrentMultiValueMap<K, V> implements MultiMap<K, V> {

	private static final long serialVersionUID = -8812312089932013780L;

	private CreatorFactory<Collection<V>> collectionFactory;

	private Map<K, Collection<V>> backendMap = new ConcurrentHashMap<K, Collection<V>>();

	private SplitReadWriteLock srwLock = new SplitReadWriteLock(32);

	private Lock readLock(Object key) {
		return srwLock.getReadLock(key);
	}

	private Lock writeLock(Object key) {
		return srwLock.getWriteLock(key);
	}

	public ConcurrentMultiValueMap() {
		this(new ArrayListFactory<V>());
	}

	public ConcurrentMultiValueMap(CreatorFactory<Collection<V>> factory) {
		collectionFactory = factory;
	}

	private Collection<V> createCollection() {
		return collectionFactory.create();
	}

	@Override
	public V removeItem(K key, V item) {
		Lock lock = writeLock(key);
		try {
			lock.lock();
			Collection<V> c = backendMap.get(key);
			if (c == null || c.remove(item)) {
				return item;
			}
		} finally {
			lock.unlock();
		}
		return null;
	}

	@Override
	public boolean putItem(K key, V value) {
		Lock lock = writeLock(key);
		try {
			lock.lock();

			Collection<V> c = backendMap.get(key);
			if (c == null) {
				c = createCollection();
				put(key, c);
			}
			return c.add(value);

		} finally {
			lock.unlock();
		}

	}

	@Override
	public boolean containsItemValue(K key, V value) {
		Lock lock = readLock(key);
		try {
			lock.lock();
			Collection<V> c = backendMap.get(key);
			if (c == null || !c.contains(value)) {
				return false;
			}
			return true;
		} finally {
			lock.unlock();
		}

	}

	public static <SK, SV> ConcurrentMultiValueMap<SK, SV> hashSetMultiValueMap() {
		return new ConcurrentMultiValueMap<SK, SV>(new HashSetFactory<SV>());
	}

	public static <SK, SV> ConcurrentMultiValueMap<SK, SV> arrayListMultiValueMap() {
		return new ConcurrentMultiValueMap<SK, SV>(new ArrayListFactory<SV>());
	}

	private static class ArrayListFactory<E> implements CreatorFactory<Collection<E>> {
		@Override
		public Collection<E> create() {
			return new ArrayList<E>();
		}
	}

	private static class HashSetFactory<E> implements CreatorFactory<Collection<E>> {
		@Override
		public Collection<E> create() {
			return new HashSet<E>();
		}
	}

	@Override
	public boolean containsKey(Object key) {
		Lock lock = readLock(key);
		try {
			lock.lock();
			return backendMap.containsKey(key);
		} finally {
			lock.unlock();
		}
	}

	/*
	 * 本方法返回的collection是不可修改的
	 * 
	 * @see java.util.Map#get(java.lang.Object)
	 */
	@Override
	public Collection<V> get(Object key) {
		Lock lock = readLock(key);
		try {
			lock.lock();
			Collection<V> c = backendMap.get(key);
			// 没有数据时返回empty collection
			c = (c == null ? createCollection() : c);
			return Collections.unmodifiableCollection(c);

		} finally {
			lock.unlock();
		}
	}

	@Override
	public Collection<V> put(K key, Collection<V> value) {
		Lock lock = writeLock(key);
		try {
			lock.lock();
			return backendMap.put(key, value);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public Collection<V> remove(Object key) {
		Lock lock = writeLock(key);
		try {
			lock.lock();
			return backendMap.remove(key);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public void putAll(Map<? extends K, ? extends Collection<V>> m) {
		for (Map.Entry<? extends K, ? extends Collection<V>> entry : m.entrySet()) {

			Lock lock = writeLock(entry.getKey());
			try {
				lock.lock();
				Collection<V> c = backendMap.get(entry.getKey());
				if (c == null) {
					c = createCollection();
					put(entry.getKey(), c);
				}
				c.addAll(entry.getValue());

			} finally {
				lock.unlock();
			}

		}
	}

	@Override
	public Collection<Collection<V>> values() {
		return backendMap.values();

	}

	@Override
	public Set<java.util.Map.Entry<K, Collection<V>>> entrySet() {
		return backendMap.entrySet();
	}

	@Override
	public Collection<V> itemValues() {
		Collection<V> c = createCollection();
		for (Map.Entry<K, Collection<V>> entry : this.entrySet()) {

			Lock lock = writeLock(entry.getKey());
			try {
				lock.lock();
				c.addAll(entry.getValue());
			} finally {
				lock.unlock();
			}

		}
		return c;
	}

	@Override
	public int size() {
		return backendMap.size();
	}

	@Override
	public boolean isEmpty() {
		return backendMap.isEmpty();
	}

	@Override
	public boolean containsValue(Object value) {
		return backendMap.containsValue(value);
	}

	@Override
	public void clear() {
		for (Map.Entry<K, Collection<V>> entry : entrySet()) {
			remove(entry.getKey());
		}
	}

	@Override
	public Set<K> keySet() {
		return backendMap.keySet();
	}
}
